#include "asciicaesarbreaker.h"
#include "ui_asciicaesarbreaker.h"

#include <QFile>
#include <QFileDialog>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QtDebug>

#include "cipher.h"
#include "task/caesarbreak.h"
#include "loadingform.h"

AsciiCaesarBreaker::AsciiCaesarBreaker(QWidget *parent) :
    QWidget(parent), ui(new Ui::AsciiCaesarBreaker), hasLoadedFreqs(false)
{
    ui->setupUi(this);
}

AsciiCaesarBreaker::~AsciiCaesarBreaker()
{
    delete ui;
}

void AsciiCaesarBreaker::on_open_cypher_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"));
    QFile input(fileName);
    input.open(QIODevice::ReadOnly);
    ui->cyphertext->setBinaryData(input.readAll());
}

void AsciiCaesarBreaker::on_open_freq_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"));
    if (fileName.isNull()) return;
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName(fileName);

    if (!db.open())
    {
        qDebug() << "impossibile aprire il file";
        return;
    }

    QSqlQuery q = db.exec("SELECT * FROM frequencies WHERE klen <= 1");
    if (!q.isActive())
    {
        qDebug() << "il file delle frequenze non è valido (la tabella \"frequencies\" non esiste)";
        return;
    }
    Cipher c;
    if (!ui->binaryMode->isChecked()) c.setAsciiMode();
    alphabet = c.alphabet();

    langFrequencies.clear();
    for (int i = 0; i < alphabet.size(); i++) langFrequencies << 0.0;

    int keyField = q.record().indexOf("key");
    int freqField = q.record().indexOf("relFreq");
    if (keyField == -1 || freqField == -1)
    {
        qDebug() << "il file delle frequenze non è valido (campi non presenti nella tabella \"frequencies\")";
        return;
    }

    while (q.next())
    {
        int i = alphabet.indexOf(q.value(keyField).toByteArray());
        if (i == -1) return;
        langFrequencies[i] = q.value(freqField).toReal();
    }

    hasLoadedFreqs = true;
    ui->break_2->setEnabled(true);
    ui->freqFileName->setText(fileName.split("/").last());
}

void AsciiCaesarBreaker::on_break_2_clicked()
{
    if (!hasLoadedFreqs) {
        qDebug() << "File delle frequenze non caricato. impossibile procedere";
        return;
    }

    QByteArray input = ui->cyphertext->binaryData();

    LoadingForm * busyLabel = new LoadingForm("Breaking Caesar...", this);
    busyLabel->move((rect().bottomRight() - busyLabel->rect().bottomRight())/2);
    busyLabel->show();

    CaesarBreak * worker = new CaesarBreak(alphabet, langFrequencies, input, this);
    connect(worker, SIGNAL(done(char,QByteArray)), this, SLOT(crackDone(char,QByteArray)));
    connect(worker, SIGNAL(finished()), busyLabel, SLOT(deleteLater()));
    worker->start();

    //TODO lock UI
}

void AsciiCaesarBreaker::crackDone(char key, QByteArray plain)
{
    ui->key->setBinaryData(QByteArray(1, key));
    ui->plaintext->setBinaryData(plain);
}
void AsciiCaesarBreaker::on_cEscape_clicked()
{
    ui->plaintext->setEscapeMode(BinaryTextEdit::CEscape);
    ui->cyphertext->setEscapeMode(BinaryTextEdit::CEscape);
    ui->key->setEscapeMode(BinaryTextEdit::CEscape);
}

void AsciiCaesarBreaker::on_URLEscape_clicked()
{
    ui->plaintext->setEscapeMode(BinaryTextEdit::URLEscape);
    ui->cyphertext->setEscapeMode(BinaryTextEdit::URLEscape);
    ui->key->setEscapeMode(BinaryTextEdit::URLEscape);
}

void AsciiCaesarBreaker::on_hex_clicked()
{
    ui->plaintext->setEscapeMode(BinaryTextEdit::Hex);
    ui->cyphertext->setEscapeMode(BinaryTextEdit::Hex);
    ui->key->setEscapeMode(BinaryTextEdit::Hex);
}

void AsciiCaesarBreaker::on_base64_clicked()
{
    ui->plaintext->setEscapeMode(BinaryTextEdit::Base64);
    ui->cyphertext->setEscapeMode(BinaryTextEdit::Base64);
    ui->key->setEscapeMode(BinaryTextEdit::Base64);
}

void AsciiCaesarBreaker::on_binaryMode_clicked(bool checked)
{
    if (checked)
    {
        if (ui->cEscape->isChecked())
            on_cEscape_clicked();
        else if (ui->URLEscape->isChecked())
            on_URLEscape_clicked();
        else if (ui->hex->isChecked())
            on_hex_clicked();
        else // ui->base64->isChecked()
            on_base64_clicked();
    }
    else
    {
        ui->plaintext->setEscapeMode(BinaryTextEdit::None);
        ui->cyphertext->setEscapeMode(BinaryTextEdit::None);
        ui->key->setEscapeMode(BinaryTextEdit::None);
    }
}

void AsciiCaesarBreaker::on_save_clicked()
{
    QString fileName = QFileDialog::getSaveFileName(this, tr("Open File"));
    QFile output(fileName);
    output.open(QIODevice::WriteOnly);
    output.write(ui->plaintext->binaryData());
}
